/**
 * CPU Workload
 */
#include <stdio.h>
#include <pthread.h>
#include "resource_model.h"
#include "cpu.h"
#include "random.h"
#include "scheduler.h"
#include "generator.h"

void cancel_cpu_workload(void *);
void *workload_cpu(void *);
void create_cpu_workload(void *);
mode *setup_utilize(cJSON *);

mode_definition_list *cpu_modes[HASHSIZE];

resource_model *setup_cpu(cJSON *json) {
  install_mode(cpu_modes, "u", setup_utilize);
  cJSON *distribution = cJSON_GetObjectItem(json, "distribution");
  if(distribution == NULL)
    {
      exit(1);
    }
  setup_rng("cpu_arrival", distribution);
  resource_model *model = malloc(sizeof(resource_model));
  if(model == NULL) {
    exit(1);
  }
  model->birth = create_cpu_workload;
  model->state = NULL;
  model->modes = initialize_modes(cpu_modes,json);
  model->cnt_modes = count_modes(json);
  return model;
}

/**
 *
 */
void create_cpu_workload(void *args) 
{  
  resource_model *model = (resource_model *)args;
  double next_arrival_ms = get_random_number("cpu_arrival");
  double job_length = get_random_number("u_length");
  event *next_birth = malloc(sizeof(event));
  if(next_birth == NULL) {
	exit(1);
  }
  mode *m = select_mode(model);
  next_birth->timestamp = ms_from_now(next_arrival_ms);  
  next_birth->job = create_cpu_workload;
  next_birth->args = args;
  next_birth->next = NULL;
  pthread_t *thread = malloc(sizeof(pthread_t));
  if(thread == NULL) {
    exit(1);
  }
  pthread_create(thread, NULL,m->function, NULL);
  pthread_detach(*thread);
  event *next_cancel = malloc(sizeof(event));
  if(next_cancel == NULL) {
    exit(1);
  }
  next_cancel->timestamp = ms_from_now(job_length);
  next_cancel->job = cancel_cpu_workload;
  next_cancel->args = (void *)thread;
  next_cancel->next = NULL;
  schedule_event(next_birth);
  schedule_event(next_cancel);
}

/**
 * The actual CPU workload
 */
void *workload_cpu(void *args) {
  unsigned int x = 0;
  while(1) {  
    if(++x%500==0) {
      pthread_testcancel();
    }  
  }
}

 /**
  * Cancels a running workload
  */
 void cancel_cpu_workload(void *args) {
   pthread_t *t = (pthread_t *)args;
   pthread_cancel(*t);
   free(t);
 }

 mode * setup_utilize(cJSON *json) {
   cJSON *json_probability = cJSON_GetObjectItem(json,"p");
   setup_rng("u_length", cJSON_GetObjectItem(json, "length"));
   mode *m = malloc(sizeof(mode));
   m->function = workload_cpu;
   m->probability = json_probability->valuedouble;
   m->key = "u";
   return m;
}
